/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright (c) 2008-2011, The KiWi Project (http://www.kiwi-project.eu)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 * - Redistributions of source code must retain the above copyright notice, 
 *   this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright notice, 
 *   this list of conditions and the following disclaimer in the documentation 
 *   and/or other materials provided with the distribution.
 * - Neither the name of the KiWi Project nor the names of its contributors 
 *   may be used to endorse or promote products derived from this software 
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 * POSSIBILITY OF SUCH DAMAGE.
 * 
 * Contributor(s):
 * sstroka
 * 
 */
package kiwi.core.servlet;

import kiwi.core.api.security.TokenManagerService;
import kiwi.core.api.user.UserService;
import kiwi.core.model.user.KiWiUser;
import org.apache.amber.oauth2.common.exception.OAuthProblemException;
import org.apache.amber.oauth2.common.exception.OAuthSystemException;
import org.apache.amber.oauth2.common.message.types.ParameterStyle;
import org.apache.amber.oauth2.rs.request.OAuthAccessResourceRequest;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * AuthorizationFilter
 *
 * @author Stephanie Stroka
 *
 */
public class AuthorizationFilter implements Filter {

	private Logger log = LoggerFactory.getLogger(AuthorizationFilter.class);

    @Inject
    private UserService userService;

    @Inject
    private TokenManagerService tokenManagerService;
	
	private String errorPage;
	private String userName;
    private String userPasswordHash;

    private KiWiUser user;


	/* (non-Javadoc)
	 * @see javax.servlet.Filter#destroy()
	 */
	public void destroy() {}


	/* TODO: this is ugly ... REFACTOR!
	 * (non-Javadoc)
	 * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
	 */
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain filterChain) throws IOException, ServletException {
		
		int i=0;

        /*log.debug("--------------- debug ------------------");
        try {
            OAuthClientRequest clientReq =  OAuthClientRequest
                    .tokenLocation("https://graph.facebook.com/oauth/access_token")
                    .setGrantType(GrantType.PASSWORD)
                    .setClientId("131804060198305")
                    .setClientSecret("3acb294b071c9aec86d60ae3daf32a93")
                    .setUsername("Steffi")
                    .setPassword("test")
                    .buildBodyMessage();
            log.debug("HTTP body: " + clientReq.getBody());

            Enumeration<String> parameterNames = ((HttpServletRequest) request).getParameterNames();
            while(parameterNames.hasMoreElements()) {
                log.debug("parameterName: " + parameterNames.nextElement());
            }
        } catch (OAuthSystemException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
        log.debug("----------------------------------------");*/

		String credentials = ((HttpServletRequest)request).getHeader("Authorization");
		if(credentials != null) {
            String credentialEncoded;
            String[] authSet = credentials.split(" ");
            if(authSet.length == 2) {
                credentialEncoded = authSet[1];
            } else {
                // broken header
                log.error("broken header");
                ((HttpServletResponse) response).sendError(HttpServletResponse.SC_BAD_REQUEST);
                return;
            }
            /* TODO: check auth type (BASIC/DIGEST/CLIENT CERT)...we want to allow DIGEST and maybe CLIENT CERT
                     for simplicity, this is tested with BASIC (...should not make any difference to DIGEST)
            */
            if(authSet[0] != null && (authSet[0].equals("Basic") || authSet[0].equals("Digest"))) {
                log.debug("credentials: " + credentialEncoded);
                byte[] credentialBytes = Base64.decodeBase64(credentialEncoded);
                if(credentialBytes != null) {
                    String credentialStr = new String(credentialBytes);
                    if(credentialStr.contains(":")) {
                        userName = credentialStr.split(":")[0];
                        userPasswordHash = credentialStr.split(":")[1];
                        log.debug("Credentials:" + credentialStr);
                        user = userService.getUserByLogin(userName);

/*                        // TODO: remove the following, this has just been added for testing until the userService handles users correctly
                        user = userService.getAnonymousUser();
                        user.setPasswordHash(userPasswordHash);
                        // TODO: ------------------------------*/

                        if(!user.getPasswordHash().equals(userPasswordHash)) {
                            log.error("password did not match");
                            ((HttpServletResponse) response).setStatus(HttpServletResponse.SC_FORBIDDEN);
                            user = userService.getAnonymousUser();
                            return;
                        }
                    }
                }
            } else if(authSet[0] != null && authSet[0].equals("ClientCertificate")) {
                // TODO: someday :)
            }
        } else if(((HttpServletRequest) request).getParameter("oauth_token") != null) {
            // what to do if we receive a token?!
            try {
                OAuthAccessResourceRequest oauthRequest = new OAuthAccessResourceRequest(((HttpServletRequest) request), ParameterStyle.QUERY);
                String token = oauthRequest.getAccessToken();

                log.debug("AccessToken received: " + token);
                user = tokenManagerService.validateAccessToken(token);

                if(user == null) {
                    log.error("AccessToken " + token + " found, but invalid");
                }
            } catch (OAuthSystemException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            } catch (OAuthProblemException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }
        } else if(((HttpServletRequest) request).getParameter("refresh_token") != null) {
            
        }

        if(user == null) {
            log.debug("No authorization or token parameter provided - logging in as anonymous user.");
            user = userService.getAnonymousUser();
        }

        userService.setCurrentUser(user);
        ((HttpServletResponse) response).setStatus(HttpServletResponse.SC_OK);
        filterChain.doFilter(request, response);
    }

	/* (non-Javadoc)
	 * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
	 */
	public void init(FilterConfig filterConfig) {
		log.debug("init AuthorizationFilter");
		if (filterConfig != null) { 
			errorPage = filterConfig.getInitParameter("error_page");
		}
	}

}
